package com.wang.web.social;

import javax.inject.Inject;
import javax.sql.DataSource;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.annotation.Scope;
import org.springframework.context.annotation.ScopedProxyMode;
import org.springframework.core.env.Environment;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.encrypt.Encryptors;
import org.springframework.security.crypto.encrypt.TextEncryptor;
import org.springframework.social.connect.ConnectionFactoryLocator;
import org.springframework.social.connect.ConnectionRepository;
import org.springframework.social.connect.UsersConnectionRepository;
import org.springframework.social.connect.jdbc.JdbcUsersConnectionRepository;
import org.springframework.social.connect.support.ConnectionFactoryRegistry;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import org.springframework.social.twitter.connect.TwitterConnectionFactory;

//import com.wang.web.connect.MyConnectController;

@Configuration
@PropertySource(value="classpath:social.properties")
//@ComponentScan(basePackages = {"com.wang.web.social"})
// The following @ActiveProfiles annotation is used for testcase.
//@ActiveProfiles(profiles = "dev")
public class ApplicationConfig {
	@Inject
	private Environment environment;

    @Inject
    private DataSource dataSource;

    @Inject
    private TextEncryptor textEncryptor;
    
	@Configuration
    @Profile("dev")
    static class Dev{
        @Bean
        public TextEncryptor textEncryptor() {
            return Encryptors.noOpText();
        }
    }

    @Configuration
    @Profile("prod")
    static class Prod {
        @Bean
        public TextEncryptor textEncryptor() {
            return Encryptors.queryableText(environment.getProperty("security.encryptPassword"),
                environment.getProperty("security.encryptSalt"));
        }

        @Inject
        private Environment environment;
    }
    
	/**
	 *  Define connection factory locator, in this sample, we will locate facebook and twitter.
	 * @return
	 */
	@Bean
	@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
	public ConnectionFactoryLocator connectionFactoryLocator() {
		ConnectionFactoryRegistry registry = new ConnectionFactoryRegistry();

		registry.addConnectionFactory(new FacebookConnectionFactory(environment
				.getProperty("social.facebook.appid"), environment
				.getProperty("social.facebook.secret")));

		registry.addConnectionFactory(new TwitterConnectionFactory(environment
				.getProperty("social.twitter.appid"), environment
				.getProperty("social.twitter.secret")));

		return registry;
	}
	
	/**
	 * To persistent conneciton information, which returned from service providers, in this case they 
	 * are facebook or twitter. We need instance JdbcUsersConnectionRepository and give it the dataSource, connection factory locator
	 * and encryptor.
	 * 
	 * For development environment, we are just using no-op text method. for production environment, probably we want use queryableText
	 * 
	 * @See noOpText()
	 * @see queryableText()
	 * 
	 * Profile annotation is used for define of run time scope.
	 * @See Profile
	 * 
	 * @return
	 */
	@Bean
	@Scope(value="singleton", proxyMode=ScopedProxyMode.INTERFACES)
    public UsersConnectionRepository usersConnectionRepository() {
		JdbcUsersConnectionRepository repository = new JdbcUsersConnectionRepository(dataSource, 
		        connectionFactoryLocator(), textEncryptor);
		//repository.setConnectionSignUp(new SimpleConnectionSignUp());
		return repository;
    }
	
	/**
	 * Construct a connection repository proxy to a request-scoped for a specific user.
	 * This case we retreive authentication information from spring security context. In real case, it very depends on 
	 * exactly authentication mechanisim.
	 * 
	 * You probably would like generate it from a customized class base your own authentication way rather then config.
	 * Or call SecurityContextHolder.getContext().setAuthentication(auth) after user is sign-in.
	 * 
	 * @return
	 */
	@Bean
	@Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
	public ConnectionRepository connectionRepository() {
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		if (authentication == null) {
			//return usersConnectionRepository().createConnectionRepository("");
			throw new IllegalStateException("Unable to get a ConnectionRepository: no user signed in");
		}
		else
		{
			return usersConnectionRepository().createConnectionRepository(authentication.getName());
		}
	}
}
